Xceed Toolkit Plus for WPF v4.6 Documentation
Sorting Data
Welcome to Xceed Toolkit Plus for WPF v4.6 > DataGrid, ListBox, Chart, AvalonDock, and PropertyGrid > Listbox control > Sorting Data

Items in a listbox can be selected both through end-user interactions and programmatically. The SelectionMode property defines how the items in a listbox can be selected through end-user interactions. SelectionMode.Single (default) indicates that only one item can be selected at a time. Multiple indicates that multiple items can be selected without pressing the CTRL or SHIFT modifier keys. Extended indicates that multiple items can be selected by pressing a modifier key.

Retrieving the Selected Items

By using the BeginGetSelectedItems and EndGetSelectedItems asynchronous methods, the items that are currently selected in a listbox can be retrieved. When dealing with a local data source (i.e., "full list"), the BeginGetSelectedItems method will return immediately and the value of the IsCompleted property of the returned IAsyncResult will be true, indicating that the operation has been completed. The EndGetSelectedItems method can then be called to finalize the process and get the selected items. If a virtualized data source is used, the EndGetSelectedItems method needs to be called in the callback after verifying whether the operation completed synchronously or not.

Private Sub GetSelectedItems()
   Dim result As IAsyncResult = Me.listBox.BeginGetSelectedItems( New AsyncCallback( AddressOf Me.ProcessSelectedItems ), Nothing )
   If( result.IsCompleted ) Then
      Dim selectedItems As IEnumerable( Of Object ) = Me.listBox.EndGetSelectedItems( result )
   End If
End Sub

Private Sub ProcessSelectedItems( ByVal result As IAsyncResult )
   If( result.CompletedSynchronously ) Then
      Return
   End If
   Dim selectedItems As IEnumerable( Of Object )  = Me.listBox.EndGetSelectedItems( result )
End Sub
private void GetSelectedItems()
{
   IAsyncResult result = this.listBox.BeginGetSelectedItems( new AsyncCallback( this.ProcessSelectedItems ), null );
   if( result.IsCompleted )
      IEnumerable<object> selectedItems = this.listBox.EndGetSelectedItems( result );
}

private void ProcessSelectedItems( IAsyncResult result )
{
   if( result.CompletedSynchronously )
      return;
   IEnumerable<object> selectedItems = this.listBox.EndGetSelectedItems( result );
}

The SelectedItems, SelectedItem, SelectedValue, and SelectedValuePath properties should only be used with sources that are not data-virtualized (asynchronous): the BeginGetSelectedItems and EndGetSelectedItems methods should be used instead if the data source is data-virtualized (asynchronous). If used with an asynchronous source, SelectedItems will throw an exception, SelectedItem and SelectedValue will always return null, and SelectedValuePath will have no effect.

Selecting Items Programmatically

Items can be selected by adding selection ranges to a listbox's SelectedRanges property. Each range that is added to the collection represents a group of items that have matched one or more selection criteria. Programmatically, a selection range can only be created if the data it is working with is sorted. In order to sort the data, one or more SortDescription objects, which will be used to create the data query that is sent to the data source, must be provided at construction time.

A selection range defines "start" and "end" range-information dictionaries that specify the start and end points of a range of selected items (see StartRangeInfos and EndRangeInfos properties). For each start/end range-information dictionary combination that is added to the selection range, a corresponding sort description, whose PropertyName property value matches the key of the start/end range-information dictionary combination, must also be provided (see examples below).

The sort descriptions used by a selection range have no impact on how the data is actually sorted in the listbox and vice-versa.

In addition, both the start/end range-information dictionaries (i.e., StartRangeInfos and EndRangeInfos, respectively) expose an IsInclusive property that determines whether the start or end range-information dictionaries are inclusive, indicating that their values are included in the selection range (default), or if they are excluded from the selection range. These properties apply to all the range-information dictionary combinations specified in the StartRangeInfos and EndRangeInfos dictionaries. 

Predicates (i.e., filter parameter in the SelectionRange ctors) are executed locally meaning that when the BeginGetSelectedItems and EndGetSelectedItems are called and a selection range that provides a predicate is used, items will be retrieved from the server in order to determine those that pass the filter.

If one or more start and end range information dictionary is provided and/or a filter expression, only the items that are not already excluded by the range information and filter expression will be retrieved.

In a virtualized environment, it is not recommended to use the filter predicate unless dealing with a very limited number of items.

Items can also be unselected by creating a selection range and setting its SelectionType property to Unselect (see Unselecting items from a selection range example below).

The following examples cover most, if not all, possible scenarios.

Selecting all items

Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( SelectionRange.All )
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( SelectionRange.All );

Selecting specific items (ShipCountry = "Germany")

Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing)
 
range.StartRangeInfos.Add( "ShipCountry", "Germany" )
range.EndRangeInfos.Add( "ShipCountry", "Germany" )
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
 
range.StartRangeInfos.Add( "ShipCountry", "Germany" );
range.EndRangeInfos.Add( "ShipCountry", "Germany" );
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

 

Selecting items within a range (ShipCountry = "A-M")

Dim range As New SelectionRange( New SortDescription() { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
 
range.StartRangeInfos.Add( "ShipCountry", "A" )
range.EndRangeInfos.Add( "ShipCountry", "N" )
 
range.EndRangeInfos.IsInclusive = False
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
 
range.StartRangeInfos.Add( "ShipCountry", "A" );
range.EndRangeInfos.Add( "ShipCountry", "N" );
 
range.EndRangeInfos.IsInclusive = false;
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

 

Selecting items using a filter expression (ShipVia !=3)

Dim expression As New FilterExpression( "ShipVia", FilterOperator.NotEqual, 3 )
 
Dim range As New SelectionRange( New SortDescription() { New SortDescription( "OrderDate", ListSortDirection.Ascending ) }, expression, Nothing )
 
range.StartRangeInfos.Add( "OrderDate", New DateTime( 2006, 01, 01 ) )
range.EndRangeInfos.Add( "OrderDate", New DateTime( 2006, 12, 31 ) )
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
FilterExpression expression = new FilterExpression( "ShipVia", FilterOperator.NotEqual, 3 );
 
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "OrderDate", ListSortDirection.Ascending ) }, expression, null );
 
range.StartRangeInfos.Add( "OrderDate", new DateTime( 2006, 01, 01 ) );
range.EndRangeInfos.Add( "OrderDate", new DateTime( 2006, 12, 31 ) );
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

 

Selecting items using combined filter expressions (ShipVia = 3 OR OrderDate >= 2008/01/01)

Dim leftExpression As New FilterExpression( "ShipVia", FilterOperator.Equal, 3 )
Dim rightExpression As New FilterExpression( "OrderDate", FilterOperator.GreaterThanOrEqual, New DateTime( 2008, 01, 01 ) )
 
Dim expression As New OrFilterExpression( leftExpression, rightExpression )
 
Dim range As New SelectionRange( expression, Nothing )
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
FilterExpression leftExpression = new FilterExpression( "ShipVia", FilterOperator.Equal, 3 );
FilterExpression rightExpression = new FilterExpression( "OrderDate", FilterOperator.GreaterThanOrEqual, new DateTime( 2008, 01, 01 ) );
 
OrFilterExpression expression = new OrFilterExpression( leftExpression, rightExpression );
 
SelectionRange range = new SelectionRange( expression, null );
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

 

Selecting items using multiple selection-range infos (ShipVia = 2 AND OrderDate = 2006)

Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipVia", ListSortDirection.Ascending ),
                                                         New SortDescription( "OrderDate", ListSortDirection.Ascending )}, Nothing, Nothing )
 
range.StartRangeInfos.Add( "ShipVia", 2 )
range.StartRangeInfos.Add( "OrderDate", New DateTime( 2006, 01, 01 ) )
 
range.EndRangeInfos.Add( "ShipVia", 2 )
range.EndRangeInfos.Add( "OrderDate", New DateTime( 2006, 12, 31 ) )
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipVia", ListSortDirection.Ascending ),
                                                                        new SortDescription( "OrderDate", ListSortDirection.Ascending )}, null, null );
 
range.StartRangeInfos.Add( "ShipVia", 2 );
range.StartRangeInfos.Add( "OrderDate", new DateTime( 2006, 01, 01 ) );
 
range.EndRangeInfos.Add( "ShipVia", 2 );
range.EndRangeInfos.Add( "OrderDate", new DateTime( 2006, 12, 31 ) );
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

 

Selecting items using a predicate delegate (ShippedDate > RequiredDate)

Dim range As New SelectionRange( Nothing, New Predicate(Of Object)( IsPastRequiredDate ) )
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
Private Function IsPastRequiredDate( ByVal value As Object ) As Boolean
  Dim order As Order = CType( value, Order )
 
   If order Is Nothing Then
      return False
   End If
 
   Return ( order.ShippedDate > order.RequiredDate )
End Function
SelectionRange range = new SelectionRange( null, new Predicate<object>( IsPastRequiredDate ) );
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );
 
private bool IsPastRequiredDate( object value )
{
   Order order = value as Order;
 
   if( order == null )
      return false;
 
   return ( order.ShippedDate > order.RequiredDate );
}

 

Selecting items using multiple selection ranges (ShipCountry = "A-D" AND ShipCountry = "M-S")

Dim firstRange As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
Dim secondRange As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
 
firstRange.StartRangeInfos.Add( "ShipCountry", "A" )
firstRange.EndRangeInfos.Add( "ShipCountry", "D" )
 
secondRange.StartRangeInfos.Add( "ShipCountry", "M" )
secondRange.EndRangeInfos.Add( "ShipCountry", "S" )
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( firstRange )
Me.listBox.SelectedRanges.Add( secondRange )
SelectionRange firstRange = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
SelectionRange secondRange = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
 
firstRange.StartRangeInfos.Add( "ShipCountry", "A" );
firstRange.EndRangeInfos.Add( "ShipCountry", "D" );
 
secondRange.StartRangeInfos.Add( "ShipCountry", "M" );
secondRange.EndRangeInfos.Add( "ShipCountry", "S" );
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( firstRange );
this.listBox.SelectedRanges.Add( secondRange );

Selecting items from start to specified end point

Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
 
' Select all items from the start to "C". All items that start with "A" or "B" will be selected.
' Using "B" only would not work since, for example, "Belgium"  "B".
range.StartRangeInfos.FromStart()
range.EndRangeInfos.Add( "ShipCountry", "C" )
range.EndRangeInfos.IsInclusive = False
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
 
// Select all items from the start to "C". All items that start with "A" or "B" will be selected.
// Using "B" only would not work since, for example, "Belgium"  "B".
range.StartRangeInfos.FromStart();
range.EndRangeInfos.Add( "ShipCountry", "C" );
range.EndRangeInfos.IsInclusive = false;
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

Selecting items from specified start point to end

Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
 
range.StartRangeInfos.Add( "ShipCountry", "B" )
range.EndRangeInfos.ToEnd()
 
Me.listBox.SelectedRanges.Clear()
Me.listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
 
range.StartRangeInfos.Add( "ShipCountry", "B" );
range.EndRangeInfos.ToEnd();
 
this.listBox.SelectedRanges.Clear();
this.listBox.SelectedRanges.Add( range );

Unselecting items from a selection range

Dim range As New SelectionRange( New SortDescription() { New SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, Nothing, Nothing )
 
range.SelectionType = SelectionType.Unselection
range.StartRangeInfos.Add( "ShipCountry", "Canada" )
range.EndRangeInfos.Add( "ShipCountry", "Canada" )
 
listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange( new SortDescription[] { new SortDescription( "ShipCountry", ListSortDirection.Ascending ) }, null, null );
 
range.SelectionType = SelectionType.Unselection;
range.StartRangeInfos.Add( "ShipCountry", "Canada" );
range.EndRangeInfos.Add( "ShipCountry", "Canada" );
 
listBox.SelectedRanges.Add( range );

 

Selecting from and to a specific item (LOCAL LIST ONLY)

Dim range As New SelectionRange()
 
range.StartRangeInfos.FromItem( Me.People[ 5 ] )
range.EndRangeInfos.ToItem( Me.People[ 10 ] )
 
listBox.SelectedRanges.Add( range )
SelectionRange range = new SelectionRange();
 
range.StartRangeInfos.FromItem( this.People[ 5 ] );
range.EndRangeInfos.ToItem( this.People[ 10 ] );
 
listBox.SelectedRanges.Add( range );

 

Selecting a single item from a remote data source (WCF DataServiceQuery)

Public Sub GetOrder( ByVal orderID As Integer )
   Dim query As DataServiceQuery( Of Order )= TryCast( Data.Orders.Where( order => order.OrderID = orderID ), DataServiceQuery( Of Order ) )
   If Not query Is Nothing Then
       Dim result As IAsyncCallback= query.BeginExecute( New AsyncCallback( AddressOf Me.ProcessItem ), query )
   End If
End Sub
 
Private Sub ProcessItem( Dim result As IAsyncResult )
   Dim query As DataServiceQuery( Of Order )= TryCast( result.AsyncState, DataServiceQuery( Of Order )
 
   If Not query Is Nothing Then
      Dim q As IEnumerable( Of Order ) = query.EndExecute( result )
      Dim order As Order = q.FirstOrDefault()
 
      Dim range = New SelectionRange( order )
 
      listBox.SelectedRanges.Clear()
      listBox.SelectedRanges.Add( range )
   End If
End Sub
Private Sub Button_Click( ByVal sender As Object, ByVal e As RoutedEventArgs )
   Dim orderIDString As String = orderIDTextBox.Text.Trim()
   If Not string.IsNullOrWhiteSpace( orderIDString ) Then
      Me.GetOrder( System.Convert.ToInt32( orderIDString ) )
   End If
End Sub
public void GetOrder( int orderID )
{
   DataServiceQuery<Order> query = Data.Orders.Where( order => order.OrderID == orderID ) as DataServiceQuery<Order>;
 
   if( query != null )
      IAsyncResult result = query.BeginExecute( new AsyncCallback( this.ProcessItem ), query ); 
}
 
private void ProcessItem( IAsyncResult result )
{
   DataServiceQuery<Order> query = result.AsyncState as DataServiceQuery<Order>;
 
   if( query != null )
   {
      IEnumerable<Order> q = query.EndExecute( result );
      Order order = q.FirstOrDefault();
 
      SelectionRange range = new SelectionRange( order );
 
      listBox.SelectedRanges.Clear();
      listBox.SelectedRanges.Add( range );
   }
}
 
private void Button_Click( object sender, RoutedEventArgs e )
{
   string orderIDString = orderIDTextBox.Text.Trim();
 
   if( !string.IsNullOrWhiteSpace( orderIDString ) )
      this.GetOrder( System.Convert.ToInt32( orderIDString ) );
}

 

Selection-Changed Notifications

Selection-changed notifications are provided via the SelectionChanged event, which is raised whenever the selection in a listbox changes, whether by end-user interaction or through programmatic modifications of the selected ranges.